#include "client_pool.h"

const unsigned int BUF_SIZE = 12288;

void init_pool(int listen_fd, client_pool *pool){   
    FD_ZERO(&pool->all_set);                // 初始化所有文件描述符 
    FD_ZERO(&pool->read_fds);               // 初始化所有可读文件描述符
    FD_SET(listen_fd, &pool->all_set);      // 将 listen_fd 加入集合之中
    pool->max_fd = listen_fd;               // 将 max_fd 初始化为 listen_fd
    pool->ready_num = 0;                    // 初始化可读客户端为0
    pool->max_idx = -1;                     // 初始化最大客户端索引为-1
    for (int i = 0; i < FD_SETSIZE; i++){   // 将数组中全部客户端描述符初始为-1
        pool->client_fds[i] = -1;
    }
}

// 将准备好的客户端加入客户池中
void add_client_to_pool(int new_fd, client_pool *pool){
    pool->ready_num++;

    int i;
    for(i=0; i<FD_SETSIZE; i++){
        if (pool->client_fds[i] < 0){
            pool->client_fds[i] = new_fd;
            FD_SET(new_fd, &pool->all_set);
            pool->max_fd = (new_fd > pool->max_fd) ? new_fd : pool->max_fd;
            pool->max_idx = (i > pool->max_idx) ? i : pool->max_idx;
            break;
        }
    }

    if(i==FD_SETSIZE){
        // dump_log("[Client pool] Too many clients!");
        printf("[Client pool] Too many clients!");
    }
}

void handle_clients(client_pool *pool){
    int i, nbytes, client_fd;
    char buf[BUF_SIZE];

    // 遍历client_fds 按顺序处理客户端
    for(i=0; (i<=pool->max_idx) && (pool->ready_num>0); i++){
        client_fd = pool->client_fds[i];
        if(client_fd <= 0)
            continue;

        if(FD_ISSET(client_fd, &pool->read_fds)){   // FD_ISSET: 检查集合中指定的文件描述符是否可以读写
            set_fl(client_fd, O_NONBLOCK);          // set_fl: 设置文件状态标志为非阻塞
            nbytes = recv(client_fd, buf, BUF_SIZE, 0);
            if(nbytes > 0){
                // dump_log("[Client pool] Receive %d bytes from client on socket %d", nbytes, client_fd);
                process_pipelined_request(client_fd, buf);  // 处理pipeline request
                clr_fl(client_fd, O_NONBLOCK);              // 清空文件状态标志
                memset(buf, 0, BUF_SIZE);
            }
            else if(nbytes<=0){
                if(nbytes==0){
                    // dump_log("[Client pool] Connection closed by client on socket %d", client_fd);
                    printf("[Client pool] Connection closed by client on socket %d\n", client_fd);
                }
                else{
                    // dump_log("[Client pool] Exception on recv() from client on socket %d", client_fd);
                    printf("[Client pool] Exception on recv() from client on socket %d\n", client_fd);
                }
                clear_client(client_fd, i, pool);
            }

            // 处理完全部客户端
            pool->ready_num--;
            if(pool->ready_num<=0)
                return;
        }
    }
}

// 删除当前客户端
void clear_client(int client_fd, int idx, client_pool *pool){
    close(client_fd);
    FD_CLR(client_fd, &pool->all_set);
    pool->client_fds[idx] = -1;
}


void set_fl(int fd, int flags){
    int val;
    if ((val = fcntl(fd, F_GETFL, 0)) < 0)
        err_sys("fcntl F_GETFL error");

    val |= flags;   // 启动指定标志位
    if (fcntl(fd, F_SETFL, val) < 0)
        err_sys("fcntl F_SETFL error");
}

void clr_fl(int fd, int flags){
    int val;
    if ((val = fcntl(fd, F_GETFL, 0)) < 0)
        err_sys("fcntl F_GETFL error");

    val &= ~flags;  // 关闭指定标志位
    if (fcntl(fd, F_SETFL, val) < 0)
        err_sys("fcntl F_SETFL error");
}

void err_sys(const char *fmt, ...){
    va_list(args);
    va_start(args, fmt);
    vprintf(fmt, args);
    printf("\n");
    va_end(args);
    exit(1);
}
